//package com.xiemulei.gulimall.search.service.impl;
//
//import co.elastic.clients.elasticsearch.ElasticsearchClient;
//import co.elastic.clients.elasticsearch._types.FieldValue;
//import co.elastic.clients.elasticsearch._types.SortOrder;
//import co.elastic.clients.elasticsearch._types.aggregations.*;
//import co.elastic.clients.elasticsearch._types.query_dsl.*;
//import co.elastic.clients.elasticsearch.core.SearchRequest;
//import co.elastic.clients.elasticsearch.core.SearchResponse;
//import co.elastic.clients.elasticsearch.core.search.Hit;
//import co.elastic.clients.json.JsonData;
//import com.alibaba.fastjson2.JSON;
//import com.alibaba.fastjson2.TypeReference;
//import com.alibaba.nacos.common.utils.CollectionUtils;
//import com.xiemulei.common.to.es.SkuEsModel;
//import com.xiemulei.common.utils.R;
//import com.xiemulei.gulimall.search.constant.EsConstant;
//import com.xiemulei.gulimall.search.feign.ProductFeignClient;
//import com.xiemulei.gulimall.search.service.MallSearchService;
//import com.xiemulei.gulimall.search.vo.AttrResponseVo;
//import com.xiemulei.gulimall.search.vo.BrandVo;
//import com.xiemulei.gulimall.search.vo.SearchParam;
//import com.xiemulei.gulimall.search.vo.SearchResult;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//import org.springframework.util.StringUtils;
//
//import javax.annotation.Resource;
//import java.io.IOException;
//import java.net.URLEncoder;
//import java.nio.charset.StandardCharsets;
//import java.util.ArrayList;
//import java.util.Arrays;
//import java.util.List;
//import java.util.stream.Collectors;
//
//@Slf4j
//@Service
//public class MallSearchServiceImpl implements MallSearchService {
//
//    @Resource
//    private ElasticsearchClient esClient;
//
//    @Resource
//    ProductFeignClient productFeignClient;
//
//    @Override
//    public SearchResult search(SearchParam param) {
//        SearchResult result = null;
//        // 1、准备检索请求
//        SearchRequest searchRequest = buildSearchRequest(param);
//        try {
//            // 2、执行检索请求
//            SearchResponse<SkuEsModel> response = esClient.search(searchRequest, SkuEsModel.class);
//            System.out.println("ElasticSearch 搜索结果：" + response);
//            // 3、分析响应数据，封装成需要的格式
//            result = buildSearchResult(response, param);
//        } catch (IOException e) {
//            log.error("数据检索异常:", e);
//        }
//
//        return result;
//    }
//
//    private SearchRequest buildSearchRequest(SearchParam param) {
//        // 构建DSL语句对象
//        SearchRequest.Builder builder = new SearchRequest.Builder();
//
//        // 模糊匹配，过滤（按照属性，分类，品牌，价格区间，库存）
//        // 1、构建bool - query
//        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
//
//        // 1.1、must【得分】
//        // 分词匹配skuTitle
//        if (StringUtils.hasLength(param.getKeyword())) {
//            boolQuery.must(MatchQuery.of(m -> m.field("skuTitle").query(param.getKeyword()))._toQuery());
//        }
//
//        // 1.2、filter【无得分】
//        // 三级分类
//        if (param.getCatalog3Id() != null) {
//            // 3级分类id过滤
//            boolQuery.filter(QueryBuilders.term(t -> t.field("catalogId").value(param.getCatalog3Id())));
//        }
//
//        // 1.3、品牌
//        if (param.getBrandIds() != null && !param.getBrandIds().isEmpty()) {
//            List<FieldValue> fieldValues = param.getBrandIds().stream().map(FieldValue::of).toList();
//            TermsQueryField termsQueryField = new TermsQueryField.Builder().value(fieldValues).build();
//            // 按照品牌 id 查询
//            boolQuery.filter(QueryBuilders.terms(t -> t.field("brandId").terms(termsQueryField)));
//        }
//
//        // 1.4、属性
//        if (!CollectionUtils.isEmpty(param.getAttrs())) {
//            // attrs=1_5寸:8寸&attrs=2_16G:8G
//            for (String attrStr : param.getAttrs()) {
//                BoolQuery.Builder nestedBoolQuery = new BoolQuery.Builder();
//                // attrs=1_5寸:8寸
//                String[] s = attrStr.split("_");
//                String attrId = s[0];
//                String[] attrValues = s[1].split(":");
//                List<FieldValue> fieldValues = Arrays.stream(attrValues).map(FieldValue::of).toList();
//                TermsQueryField termsQueryField = new TermsQueryField.Builder().value(fieldValues).build();
//                // must中的必须是同时满足的，如果boolQuery不是内层的
//                // 那么boolQuery会拼接多个must(attrs.attrId)，例如id = 6时，同时必须id = 7，没有此attr
//                nestedBoolQuery.must(QueryBuilders.term(t -> t.field("attrs.attrId").value(attrId)));
//                nestedBoolQuery.must(QueryBuilders.terms(t -> t.field("attrs.attrValue").terms(termsQueryField)));
//                // 每一个属性都要生成一个嵌入式查询
//                // 商品必须包含每一个 传入的属性
//                Query query = QueryBuilders.nested(n -> n.path("attrs").query(nestedBoolQuery.build()._toQuery()).scoreMode(ChildScoreMode.None));
//                boolQuery.filter(query);
//            }
//        }
//
//        // 1.5、库存
//        if (param.getHasStock() != null && param.getHasStock() == 1) {
//            boolQuery.filter(QueryBuilders.term(t -> t.field("hasStock").value(true))); // 按是否有库存查询
////            boolQuery.filter(QueryBuilders.termQuery("hasStock", param.getHasStock() == 1)); // 按是否有库存查询
//        }
//
//        // 1.6、价格区间 0_500  _500  500_
//        if (StringUtils.hasLength(param.getSkuPrice())) {
//            RangeQuery.Builder rangeQuery = QueryBuilders.range().field("skuPrice");
//
//            String[] s = param.getSkuPrice().split("_");
//            if (s.length == 2) {
//                rangeQuery.gte(JsonData.fromJson(s[0])).lte(JsonData.fromJson(s[1]));
//            } else if (s.length == 1) {
//                if (param.getSkuPrice().startsWith("_")) {
//                    rangeQuery.lte(JsonData.fromJson(s[0]));
//                }
//                if (param.getSkuPrice().endsWith("_")) {
//                    rangeQuery.gte(JsonData.fromJson(s[0]));
//                }
//            }
//            boolQuery.filter(rangeQuery.build()._toQuery());
//        }
//
//
//        builder.query(boolQuery.build()._toQuery());
//
//        // 排序
//        if (StringUtils.hasLength(param.getSort())) {
//            String[] s = param.getSort().split("_");
//            SortOrder order = s[1].equalsIgnoreCase("asc") ? SortOrder.Asc : SortOrder.Desc;
//            builder.sort(t -> t.field(f -> f.field(s[0]).order(order)));
//        }
//
//        // 分页
//        // from = (pageNumber - 1) * size
//        if (param.getPageNum() != null) {
//            builder.from((param.getPageNum() - 1) * EsConstant.PRODUCT_PAGESIZE);
//            builder.size(EsConstant.PRODUCT_PAGESIZE);
//        }
//
//        // TODO 高亮 只有传了 keyword
////        if (StringUtils.hasLength(param.getKeyword())) {
////            Highlight.Builder highlightBuilder = new Highlight.Builder();
////            highlightBuilder.fields("skuTitle");
////            highlightBuilder.
////            highlightBuilder.preTags("<b style='color:red'>");
////            highlightBuilder.postTags("</b>");
////            sourceBuilder.highlight(highlightBuilder.build());
////        }
//
//        // 聚合分析
//        // 1.品牌聚合
//        TermsAggregation.Builder brand_agg = AggregationBuilders.terms().name("brand_agg");
//        brand_agg.field("brandId").size(50);
//        // 品牌聚合的子组合
//        brand_agg.
//                brand_agg.subAggregation(AggregationBuilders.terms().name("brand_name_agg").field("brandName").size(1));
//        brand_agg.subAggregation(AggregationBuilders.terms().name("brand_img_agg").field("brandImg").size(1));
//        builder.aggregation(brand_agg);
//
//        // 分类聚合
//        TermsAggregation.Builder catalog_agg = AggregationBuilders.terms().name("catalog_agg");
//        catalog_agg.field("catalogId").size(20);
//        catalog_agg.subAggregation(AggregationBuilders.terms().name("catalog_name_agg").field("catalogName").size(1));
//        builder.aggregation(catalog_agg);
//
//        // 属性聚合
//        Aggregation attr_agg = AggregationBuilders.nested("attr_agg", "attrs");
//        TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
//        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));
//        attr_id_agg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));
//        attr_agg.subAggregation(attr_id_agg);
//        builder.aggregation(attr_agg);
//
//
//        String s = builder.toString();
//        System.out.println(s);
//
//        builder
//        return SearchRequest.of(builder);
//    }
//
//    private SearchResult buildSearchResult(SearchResponse<SkuEsModel> response, SearchParam param) {
//        SearchResult result = new SearchResult();
//
//        List<Hit<SkuEsModel>> hits = response.hits().hits();
//
//        // 1、返回所有查询到的商品
//        List<SkuEsModel> esModels = new ArrayList<>();
//        if (!CollectionUtils.isEmpty(hits)) {
//            for (Hit<SkuEsModel> hit : hits) {
//                String sourceAsString = hit.source().toString();
//                System.out.println("商品信息：" + sourceAsString);
//                SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
//                if (StringUtils.hasLength(param.getKeyword())) {
//                    // 设置高亮
//                    List<String> skuTitle = hit.highlight().get("skuTitle");
////                    HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");
//                    String string = skuTitle.get(0);
//                    esModel.setSkuTitle(string);
//                }
//                esModels.add(esModel);
//            }
//        }
//        result.setProducts(esModels);
//
//        // 2、当前所有商品涉及到的所有属性信息
//        List<SearchResult.AttrVo> attrVos = new ArrayList<>();
//        Aggregate attr_agg = response.aggregations().get("attr_agg");
//        Aggregate attr_id_agg = response.aggregations().get("attr_id_agg");
//        for (HistogramBucket bucket : attr_id_agg.histogram().buckets().array()) {
//            SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
//            long attr_id = (long) bucket.key();
//
//            Aggregate attr_name_agg = bucket.aggregations().get("attr_name_agg");
//            String attr_name = attr_name_agg.histogram().buckets().array().get(0).keyAsString();
//
//            Aggregate attr_value_agg = bucket.aggregations().get("attr_value_agg");
//            List<String> attrValues = attr_value_agg.getBuckets().stream().map(MultiBucketsAggregation.Bucket::getKeyAsString).collect(Collectors.toList());
//
//            attrVo.setAttrId(attr_id);
//            attrVo.setAttrName(attr_name);
//            attrVo.setAttrValue(attrValues);
//
//            attrVos.add(attrVo);
//        }
//        result.setAttrs(attrVos);
//
//        // 3、当前所有商品涉及到的所有品牌信息
//        List<SearchResult.BrandVo> brandVos = new ArrayList<>();
//        Aggregate brandAgg = response.aggregations().get("brand_agg");
//        for (Terms.Bucket bucket : brandAgg.getBuckets()) {
//            SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
//            // 提取品牌ID
//            brandVo.setBrandId(bucket.getKeyAsNumber().longValue());
//            // 提取品牌名字
//            ParsedStringTerms brand_name_agg = bucket.getAggregations().get("brand_name_agg");
//            brandVo.setBrandName(brand_name_agg.getBuckets().get(0).getKeyAsString());
//            // 提取品牌图片
//            ParsedStringTerms brand_img_agg = bucket.getAggregations().get("brand_img_agg");
//            brandVo.setBrandImg(brand_img_agg.getBuckets().get(0).getKeyAsString());
//            brandVos.add(brandVo);
//        }
//        result.setBrands(brandVos);
//
//        // 4、当前所有商品涉及到的所有分类信息
//        Aggregate catalog_agg = response.aggregations().get("catalog_agg");
//        List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();
//        catalog_agg.bucketMetricValue().keys()
//        List<? extends Terms.Bucket> buckets = catalog_agg.getBuckets();
//        for (Terms.Bucket bucket : buckets) {
//            SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
//            // 提取分类Id
//            catalogVo.setCatalogId(Long.parseLong(bucket.getKeyAsString()));
//            // 提取分类名字
//            ParsedStringTerms catalog_name_agg = bucket.getAggregations().get("catalog_name_agg");
//            catalogVo.setCatalogName(catalog_name_agg.getBuckets().get(0).getKeyAsString());
//            catalogVos.add(catalogVo);
//        }
//        result.setCatalogs(catalogVos);
//
//
//        // 5、分页信息   pageNum:当前页码 、total:总记录数 、totalPages: 总页码
//        long total = hits.size();
//        int totalPages = (int) total % EsConstant.PRODUCT_PAGESIZE == 0 ? (int) total / EsConstant.PRODUCT_PAGESIZE : ((int) total / EsConstant.PRODUCT_PAGESIZE + 1);
//        result.setPageNum(param.getPageNum());
//        result.setTotal(total);
//        result.setTotalPages(totalPages);
//
//        // 6、所有页码数
//        List<Integer> pageNavs = new ArrayList<>();
//        for (int i = 1; i <= totalPages; i++) {
//            pageNavs.add(i);
//        }
//
//        result.setPageNavs(pageNavs);
//
//        // 7、构建面包屑导航功能
//        if (param.getAttrs() != null && param.getAttrs().size() > 0) {
//            List<SearchResult.NavVo> collect = param.getAttrs().stream().map(attr -> {
//                //1、分析每一个attrs传过来的参数值
//                SearchResult.NavVo navVo = new SearchResult.NavVo();
//                // attrs=2_5寸:6寸
//                String[] s = attr.split("_");
//                navVo.setNavValue(s[1]);
//                R r = productFeignClient.attrInfo(Long.parseLong(s[0]));
//                // 根据请求构造面包屑 规格属性Id集合，这个集合包含的属性规格不显示【前端会遍历每个参数显示】
//                result.getAttrIds().add(Long.parseLong(s[0]));
//                if (r.getCode() == 0) {
//                    AttrResponseVo data = r.getData("attr", new TypeReference<>() {
//                    });
//                    // 设置属性名
//                    navVo.setNavName(data.getAttrName());
//                } else {
//                    navVo.setNavName(s[0]);
//                }
//                //2、取消了这个面包屑以后，我们要跳转到哪个地方，将请求的地址url里面的当前置空
//                //拿到所有的查询条件，去掉当前
//                String replace = replaceQueryString(param, attr, "attrs");
//                navVo.setLink("http://search.gulimall.com/list.html?" + replace);
//
//                return navVo;
//            }).collect(Collectors.toList());
//
//            result.setNavs(collect);
//        }
//
//        // 品牌、分类
//        if (param.getBrandIds() != null && param.getBrandIds().size() > 0) {
//            List<SearchResult.NavVo> navs = result.getNavs();
//            SearchResult.NavVo navVo = new SearchResult.NavVo();
//            navVo.setNavName("品牌");
//            // 远程查询所有品牌
//            R r = productFeignClient.brandsInfo(param.getBrandIds());
//            if (r.getCode() == 0) {
//                List<BrandVo> brands = r.getData("brands", new TypeReference<>() {
//                });
//                StringBuilder builder = new StringBuilder();
//                String replace = "";
//                for (BrandVo brandVo : brands) {
//                    builder.append(brandVo.getBrandName()).append(";");
//                    replace = replaceQueryString(param, brandVo.getBrandId() + "", "brandId");
//                }
//                navVo.setNavValue(builder.toString());
//                navVo.setLink("http://search.guilimall.com/list.html?" + replace);
//            }
//            navs.add(navVo);
//        }
//
//        //TODO 分类，不需要导航取消
//
//
//        return result;
//    }
//
//    private String replaceQueryString(SearchParam param, String value, String key) {
//        String encode;
//        encode = URLEncoder.encode(value, StandardCharsets.UTF_8);
//        encode = encode.replace("+", "%20");  //浏览器对空格的编码和Java不一样，差异化处理
//        // 就是点了X之后，应该跳转的地址
//        // 这里要判断一下，attrs是不是第一个参数，因为第一个参数 没有&符号
//        // TODO BUG，第一个参数不带&
//        return param.get_queryString().replace("&" + key + "=" + encode, "");
//    }
//
//
//}
